package MathLib.MyMatrices;


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Scanner;

public class CMatrix implements IMatrix, Cloneable{
	 //����
    protected double[][] Matrix;
    protected int n; // ��������
    protected int m; // �����
    
    //������������
    
    public CMatrix(){
        this.Matrix = null;
        this.m = 0;
        this.n = 0;
    }
    
    public CMatrix(CMatrix A){
        this.m = A.m;
        this.n = A.n;
        this.Matrix = new double[m][n];
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    this.Matrix[i][j] = A.Matrix[i][j];
                }
             }
    }
    
    public CMatrix(int n){
        this.m = this.n = n; // ��������� �� ������ ��������
        this.Matrix = new double[n][n];
    }
    
    public CMatrix(int m, int n){
        this.m = m;
        this.n = n;
        this.Matrix = new double[m][n];
    }
        
    public CMatrix(double[][] matrix2) {
    	this.n = matrix2.length;
        this.m = matrix2[0].length;
        this.Matrix = new double[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    this.Matrix[i][j] = matrix2[i][j];
                }
             }
	}

	// ������
    @Override
    public void AddToThis(CMatrix A) throws MatrixEception{
        if ((this.m != A.m)||(this.n != A.n)) throw new MatrixEception(0);
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                this.Matrix[i][j] += A.Matrix[i][j];
            }
        }
    }

    @Override
    public void AddToThis(CMatrix A, CMatrix B) throws MatrixEception {
        if ((B.m != A.m)||(B.n != A.n)) throw new MatrixEception(0);
        if ((this.m != A.m)||(this.n != A.n)){
            this.m = A.m;
            this.n = A.n;
            this.Matrix = new double[m][n];
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                this.Matrix[i][j] = A.Matrix[i][j] + B.Matrix[i][j];
            }
        }
    }

    public static CMatrix Add(CMatrix A, CMatrix B) throws MatrixEception {
        if ((B.m != A.m)||(B.n != A.n)) throw new MatrixEception(0);
        CMatrix res = new CMatrix(A.m, A.n);
        
        int n = A.n;
        int m = A.m;
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                res.Matrix[i][j] = A.Matrix[i][j] + B.Matrix[i][j];
            }
        }
        
        return res;
    }

    @Override
    public CMatrix Add(CMatrix A) throws MatrixEception {
        if ((this.m != A.m)||(this.n != A.n)) throw new MatrixEception(0);
        CMatrix res = new CMatrix(m, n);
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                res.Matrix[i][j] = A.Matrix[i][j] + this.Matrix[i][j];
            }
        }
        
        return res;
    }

    @Override
    public void SubstructFromThis(CMatrix A) throws MatrixEception {
        if ((this.m != A.m)||(this.n != A.n)) throw new MatrixEception(0);
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                this.Matrix[i][j] -= A.Matrix[i][j];
            }
        }
    }

    @Override
    public void SubstructFromThis(CMatrix A, CMatrix B) throws MatrixEception {
        if ((B.m != A.m)||(B.n != A.n)) throw new MatrixEception(0);
        if ((this.m != A.m)||(this.n != A.n)){
            this.m = A.m;
            this.n = A.n;
            this.Matrix = new double[m][n];
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                this.Matrix[i][j] = A.Matrix[i][j] - B.Matrix[i][j];
            }
        }
    }

    public static CMatrix Substruct(CMatrix A, CMatrix B) throws MatrixEception {
        if ((B.m != A.m)||(B.n != A.n)) throw new MatrixEception(0);
        CMatrix res = new CMatrix(A.m, A.n);
        
        int n = A.n;
        int m = A.m;
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                res.Matrix[i][j] = A.Matrix[i][j] - B.Matrix[i][j];
            }
        }
        
        return res;
    }

    @Override
    public CMatrix Substruct(CMatrix A) throws MatrixEception {
        if ((this.m != A.m)||(this.n != A.n)) throw new MatrixEception(0);
        CMatrix res = new CMatrix(m, n);
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                res.Matrix[i][j] = A.Matrix[i][j] - this.Matrix[i][j];
            }
        }
        
        return res;
    }

    @Override
    public void MultiplyOnThis(CMatrix A) throws MatrixEception {
        if ((this.m != A.m)||(this.n != A.n)) throw new MatrixEception(0);                
        
        CMatrix C = new CMatrix(m,n);
	for(int i=0; i<m;i++){
		for(int j=0; j<n;j++){
                    int temp=0;
			for(int k=0; k<n;k++){
                            temp+= this.Matrix[i][k] * A.Matrix[k][j];
			}
                    C.Matrix[i][j]=temp;
		}
	}
	this.Matrix = C.Matrix;
    }

    @Override
    public void MultiplyOnThis(CMatrix A, CMatrix B) throws MatrixEception {
        if ((B.m != A.m)||(B.n != A.n)) throw new MatrixEception(0);
        if ((this.m != A.m)||(this.n != A.n)){
            this.m = A.m;
            this.n = A.n;
            this.Matrix = new double[m][n];
        }
        
        CMatrix C = new CMatrix(m,n);
	for(int i=0; i<m;i++){
		for(int j=0; j<n;j++){
                    int temp=0;
			for(int k=0; k<n;k++){
                            temp+= this.Matrix[i][k] * A.Matrix[k][j];
			}
                    C.Matrix[i][j]=temp;
		}
	}
	this.Matrix = C.Matrix;
    }

    public static CMatrix Multiply(CMatrix A, CMatrix B) throws MatrixEception {
        if ((B.m != A.m)||(B.n != A.n)) throw new MatrixEception(0);
        
        int n = A.n, m = A.m;
        
        CMatrix C = new CMatrix(m,n);
	for(int i=0; i<m;i++){
		for(int j=0; j<n;j++){
                    int temp=0;
			for(int k=0; k<n;k++){
                            temp+= A.Matrix[i][k] * B.Matrix[k][j];
			}
                    C.Matrix[i][j]=temp;
		}
	}
	return C;
    }

    @Override
    public CMatrix Multiply(CMatrix A) throws MatrixEception {
        if ((this.m != A.m)||(this.n != A.n)) throw new MatrixEception(0);                
        
        CMatrix C = new CMatrix(m,n);
	for(int i=0; i<m;i++){
		for(int j=0; j<n;j++){
                    int temp=0;
			for(int k=0; k<n;k++){
                            temp+= this.Matrix[i][k] * A.Matrix[k][j];
			}
                    C.Matrix[i][j]=temp;
		}
	}
	return C;
    }
    
    @Override
    public void readMatrix(InputStream in){
        Scanner datainput = new Scanner(in);
             for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    Matrix[i][j] = datainput.nextDouble();
                }
             }
    }
    
    public void readMatrix(FileInputStream in){
        Scanner datainput = new Scanner(in);
             for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    Matrix[i][j] = datainput.nextDouble();
                }
             }
    }
    
    @Override
    public void printMatrix(OutputStream out) {
        PrintWriter output = new PrintWriter(out);
        for (int i = 0; i < m; i++) {
             for (int j = 0; j < n; j++) {
                 output.print(Matrix[i][j] + "\t");
             }
             output.println();
         }
    }
    
    public void printMatrix(FileOutputStream out) {
        PrintWriter output = new PrintWriter(out);
        for (int i = 0; i < m; i++) {
             for (int j = 0; j < n; j++) {
                 output.print(Matrix[i][j] + "\t");
             }
             output.println();
         }
    }

    /*��� ������� ����� ���� �������*/
    public boolean IsKvadratna()
    { 
        return (n==m);
    }

    public boolean IsDiagonal() {
    	if(m!=n)return false;
        for (int i = 0; i < n; i++){
            for (int j = 0; j < m; j++){
                if (i != j){
                    if (this.Matrix[i][j] != 0) return false;
                }
            }
        }
        return true;
    }

    public boolean IsNullMatrix() { 
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                if (this.Matrix[i][j] != 0) return false;
            }
        }
        return true;
    }

    public boolean IsOne() {
    	if(m!=n)return false;
        for (int i = 0; i < n; i++){
            for (int j = 0; j < m; j++){
                if (i != j){
                    if (this.Matrix[i][j] != 0) return false;
                }
                else {
                    if (this.Matrix[i][j] != 1) return false;
                }
            }
        }
        return true;
    }

    public boolean IsSumetr() {
    	if(m!=n)return false;
            for (int i = 0; i < n; i++){
                for (int j = i + 1; j < m; j++){
                    if (this.Matrix[i][j] != this.Matrix[j][i]) { return false; }
                }
            }        
        return true;
    }

    public boolean IsUpperTriang() {
    	if(m!=n)return false;
        for (int i = 0; i < n; i++){
            for (int j = 0; j < i; j++){
                if (this.Matrix[i][j] != 0) { return false; }
            }
        }
        return true;
    }

    public boolean IsLowerTriang(){
        for (int i = 0; i < n; i++){
            for (int j = i+1; j < m; j++){
                if (this.Matrix[i][j] != 0) { return false; }
            }
        }
        return true;
    }
    
    
    
    /**********************************/
    
    @Override
    public String toString() {
        String res = new String();
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                res = res +"\t"+ Matrix[i][j];
            }
            res = res + "\n";
        }
        return res;
    }
    
    @Override
    public Object clone(){
    	return new CMatrix(this);
    }
    
    public double get(int i,int j) {
		return Matrix[i][j];
	}
    
    public void set(int i,int j,double x) {
		Matrix[i][j] = x;
	}
    

}




